home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cvs / dist / src / subr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-06  |  8.1 KB  |  385 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: subr.c,v 1.14.1.2 91/01/29 19:46:20 berliner Exp $";
  3. #endif !lint
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  * Various useful functions for the CVS support code.
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/file.h>
  17. #include <varargs.h>
  18. #include "cvs.h"
  19.  
  20. /*
  21.  * Send a "printf" format string to stderr and die, calling the
  22.  * defined exit function first, if necessary
  23.  */
  24. error(doperror, fmt, va_alist)
  25.     int doperror;
  26.     char *fmt;
  27.     va_dcl
  28. {
  29.     extern int errno;
  30.     va_list x1;
  31.     int err = errno;
  32.  
  33.     va_start(x1);
  34.     (void) fprintf(stderr, "%s: ", progname);
  35.     (void) vfprintf(stderr, fmt, x1);
  36.     if (doperror) {
  37.     (void) fprintf(stderr, ": ");
  38.     errno = err;
  39.     perror("");
  40.     errno = 0;
  41.     } else
  42.     (void) fprintf(stderr, "\n");
  43.     va_end(x1);
  44.     Lock_Cleanup(0);
  45.     exit(1);
  46. }
  47.  
  48. /*
  49.  * Like error() above, but just display the message to stderr,
  50.  * without dying or running the exit function.
  51.  */
  52. warn(doperror, fmt, va_alist)
  53.     int doperror;
  54.     char *fmt;
  55.     va_dcl
  56. {
  57.     extern int errno;
  58.     va_list x1;
  59.     int err = errno;
  60.  
  61.     va_start(x1);
  62.     (void) fprintf(stderr, "%s: ", progname);
  63.     (void) vfprintf(stderr, fmt, x1);
  64.     if (doperror) {
  65.     (void) fprintf(stderr, ": ");
  66.     errno = err;
  67.     perror("");
  68.     errno = 0;
  69.     } else
  70.     (void) fprintf(stderr, "\n");
  71.     va_end(x1);
  72. }
  73.  
  74. /*
  75.  * Copies "from" to "to".
  76.  * mallocs a buffer large enough to hold the entire file and
  77.  * does one read/one write to do the copy.  This is reasonable,
  78.  * since source files are typically not too large.
  79.  */
  80. copy_file(from, to)
  81.     char *from;
  82.     char *to;
  83. {
  84.     struct stat sb;
  85.     int fdin, fdout;
  86.     char *buf;
  87.  
  88.     if ((fdin = open(from, O_RDONLY)) < 0)
  89.     error(1, "cannot open %s for copying", from);
  90.     if (fstat(fdin, &sb) < 0)
  91.     error(1, "cannot fstat %s", from);
  92.     if ((fdout = creat(to, (int) sb.st_mode & 07777)) < 0)
  93.     error(1, "cannot create %s for copying", to);
  94.     if (sb.st_size > 0) {
  95.     buf = xmalloc((int)sb.st_size);
  96.     if (read(fdin, buf, (int)sb.st_size) != (int)sb.st_size)
  97.         error(1, "cannot read file %s for copying", from);
  98.     if (write(fdout, buf, (int)sb.st_size) != (int)sb.st_size)
  99.         error(1, "cannot write file %s for copying", to);
  100.     free(buf);
  101.     }
  102.     (void) close(fdin);
  103.     (void) close(fdout);
  104. }
  105.  
  106. /*
  107.  * Returns non-zero if the argument file is a directory, or
  108.  * is a symbolic link which points to a directory.
  109.  */
  110. isdir(file)
  111.     char *file;
  112. {
  113.     struct stat sb;
  114.  
  115.     if (stat(file, &sb) < 0)
  116.     return (0);
  117.     return ((sb.st_mode & S_IFMT) == S_IFDIR);
  118. }
  119.  
  120. /*
  121.  * Returns non-zero if the argument file is a symbolic link.
  122.  */
  123. islink(file)
  124.     char *file;
  125. {
  126.     struct stat sb;
  127.  
  128. #ifdef S_IFLNK
  129.     if (lstat(file, &sb) < 0)
  130.     return (0);
  131.     return ((sb.st_mode & S_IFMT) == S_IFLNK);
  132. #else
  133.     return (0);
  134. #endif
  135. }
  136.  
  137. /*
  138.  * Returns non-zero if the argument file exists.
  139.  */
  140. isfile(file)
  141.     char *file;
  142. {
  143.     struct stat sb;
  144.  
  145.     if (stat(file, &sb) < 0)
  146.     return (0);
  147.     return (1);
  148. }
  149.  
  150. /*
  151.  * Returns non-zero if the argument file is readable.
  152.  * XXX - muct be careful if "cvs" is ever made setuid!
  153.  */
  154. isreadable(file)
  155.     char *file;
  156. {
  157.     return (access(file, R_OK) != -1);
  158. }
  159.  
  160. /*
  161.  * Returns non-zero if the argument file is writable
  162.  * XXX - muct be careful if "cvs" is ever made setuid!
  163.  */
  164. iswritable(file)
  165.     char *file;
  166. {
  167.     return (access(file, W_OK) != -1);
  168. }
  169.  
  170. /*
  171.  * Open a file and die if it fails
  172.  */
  173. FILE *
  174. open_file(name, mode)
  175.     char *name;
  176.     char *mode;
  177. {
  178.     FILE *fp;
  179.  
  180.     if ((fp = fopen(name, mode)) == NULL)
  181.     error(1, "cannot open %s", name);
  182.     return (fp);
  183. }
  184.  
  185. /*
  186.  * Make a directory and die if it fails
  187.  */
  188. make_directory(name)
  189.     char *name;
  190. {
  191.     if (mkdir(name, 0777) < 0)
  192.     error(1, "cannot make directory %s", name);
  193. }
  194.  
  195. /*
  196.  * malloc some data and die if it fails
  197.  */
  198. char *
  199. xmalloc(bytes)
  200.     int bytes;
  201. {
  202.     extern char *malloc();
  203.     char *cp;
  204.  
  205.     if (bytes <= 0)
  206.     error(0, "bad malloc size %d", bytes);
  207.     if ((cp = malloc((unsigned)bytes)) == NULL)
  208.     error(0, "malloc failed");
  209.     return (cp);
  210. }
  211.  
  212.  
  213. /*
  214.  * ppstrcmp() is a front-end for strcmp() when the arguments
  215.  * are pointers to pointers to chars.
  216.  */
  217. ppstrcmp(pp1, pp2)
  218.     register char **pp1, **pp2;
  219. {
  220.     return (strcmp(*pp1, *pp2));
  221. }
  222.  
  223. /*
  224.  * ppstrcmp_files() is a front-end for strcmp() when the arguments
  225.  * are pointers to pointers to chars.
  226.  * For some reason, the ppstrcmp() above sorts in reverse order when
  227.  * called from Entries2Files().
  228.  */
  229. ppstrcmp_files(pp1, pp2)
  230.     register char **pp1, **pp2;
  231. {
  232.     /*
  233.      * Reversing the arguments here cause for the
  234.      * correct alphabetical order sort, as we desire.
  235.      */
  236.     return (strcmp(*pp2, *pp1));
  237. }
  238.  
  239. /* Some UNIX distributions don't include these in their stat.h */
  240. #ifndef S_IWRITE
  241. #define    S_IWRITE    0000200        /* write permission, owner */
  242. #endif !S_IWRITE
  243. #ifndef S_IWGRP
  244. #define    S_IWGRP        0000020        /* write permission, grougroup */
  245. #endif !S_IWGRP
  246. #ifndef S_IWOTH
  247. #define    S_IWOTH        0000002        /* write permission, other */
  248. #endif !S_IWOTH
  249.  
  250. /*
  251.  * Change the mode of a file, either adding write permissions, or
  252.  * removing all write permissions.  Adding write permissions honors
  253.  * the current umask setting.
  254.  */
  255. xchmod(fname, writable)
  256.     char *fname;
  257.     int writable;
  258. {
  259.     struct stat sb;
  260.     int mode, oumask;
  261.  
  262.     if (stat(fname, &sb) < 0) {
  263.     warn(1, "cannot stat %s", fname);
  264.     return;
  265.     }
  266.     if (writable) {
  267.     oumask = umask(0);
  268.     (void) umask(oumask);
  269.     mode = sb.st_mode | ((S_IWRITE|S_IWGRP|S_IWOTH) & ~oumask);
  270.     } else {
  271.     mode = sb.st_mode & ~(S_IWRITE|S_IWGRP|S_IWOTH);
  272.     }
  273.     if (chmod(fname, mode) < 0)
  274.     warn(1, "cannot change mode of file %s", fname);
  275. }
  276.  
  277. /*
  278.  * Rename a file and die if it fails
  279.  */
  280. rename_file(from, to)
  281.     char *from;
  282.     char *to;
  283. {
  284.     if (rename(from, to) < 0)
  285.     error(1, "cannot rename file %s to %s", from, to);
  286. }
  287.  
  288. /*
  289.  * Compare "file1" to "file2".
  290.  * Return non-zero if they don't compare exactly.
  291.  *
  292.  * mallocs a buffer large enough to hold the entire file and
  293.  * does two reads to load the buffer and calls bcmp to do the cmp.
  294.  * This is reasonable, since source files are typically not too large.
  295.  */
  296. xcmp(file1, file2)
  297.     char *file1;
  298.     char *file2;
  299. {
  300.     register char *buf1, *buf2;
  301.     struct stat sb;
  302.     off_t size;
  303.     int ret, fd1, fd2;
  304.  
  305.     if ((fd1 = open(file1, O_RDONLY)) < 0)
  306.     error(1, "cannot open file %s for comparing", file1);
  307.     if ((fd2 = open(file2, O_RDONLY)) < 0)
  308.     error(1, "cannot open file %s for comparing", file2);
  309.     if (fstat(fd1, &sb) < 0)
  310.     error(1, "cannot fstat %s", file1);
  311.     size = sb.st_size;
  312.     if (fstat(fd2, &sb) < 0)
  313.     error(1, "cannot fstat %s", file2);
  314.     if (size == sb.st_size) {
  315.     if (size == 0)
  316.         ret = 0;
  317.     else {
  318.         buf1 = xmalloc((int)size);
  319.         buf2 = xmalloc((int)size);
  320.         if (read(fd1, buf1, (int)size) != (int)size)
  321.         error(1, "cannot read file %s cor comparing", file1);
  322.         if (read(fd2, buf2, (int)size) != (int)size)
  323.         error(1, "cannot read file %s for comparing", file2);
  324.         ret = bcmp(buf1, buf2, (int)size);
  325.         free(buf1);
  326.         free(buf2);
  327.     }
  328.     } else
  329.     ret = 1;
  330.     (void) close(fd1);
  331.     (void) close(fd2);
  332.     return (ret);
  333. }
  334.  
  335. /*
  336.  * Recover the space allocated by Find_Names() and line2argv()
  337.  */
  338. free_names(pargc, argv)
  339.     int *pargc;
  340.     char *argv[];
  341. {
  342.     register int i;
  343.  
  344.     for (i = 0; i < *pargc; i++) {    /* only do through *pargc */
  345.     free(argv[i]);
  346.     }
  347.     *pargc = 0;                /* and set it to zero when done */
  348. }
  349.  
  350. /*
  351.  * Convert a line into argc/argv components and return the result in
  352.  * the arguments as passed.  Use free_names() to return the memory
  353.  * allocated here back to the free pool.
  354.  */
  355. line2argv(pargc, argv, line)
  356.     int *pargc;
  357.     char *argv[];
  358.     char *line;
  359. {
  360.     char *cp;
  361.  
  362.     *pargc = 0;
  363.     for (cp = strtok(line, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  364.     argv[*pargc] = xmalloc(strlen(cp) + 1);
  365.     (void) strcpy(argv[*pargc], cp);
  366.     (*pargc)++;
  367.     }
  368. }
  369.  
  370. /*
  371.  * Returns the number of dots ('.') found in an RCS revision number
  372.  */
  373. numdots(s)
  374.     char *s;
  375. {
  376.     char *cp;
  377.     int dots = 0;
  378.  
  379.     for (cp = s; *cp; cp++) {
  380.     if (*cp == '.')
  381.         dots++;
  382.     }
  383.     return (dots);
  384. }
  385.